/**
 ******************************************************************************
 * @file    at6558r.c
 * @brief   at6558r program body
 ******************************************************************************
 * @attention GPS芯片
 ******************************************************************************
 */
/* Includes ------------------------------------------------------------------*/
#include "at6558r.h"

#include <stdio.h>
#include <string.h>
#include "gpio.h"
#include "usart.h"

#include "debug.h"
#include "delay.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/**
 * NMEA 自定义消息
 */
#define GPS_BAUD_RATE "PCAS01,1"
#define GPS_UPDATE_RATE "PCAS02,1000"
#define GPS_MODE "PCAS04,3"

#define GPS_EN_PIN_H HAL_GPIO_WritePin(GPS_EN_GPIO_Port, GPS_EN_Pin, GPIO_PIN_SET)
#define GPS_EN_PIN_L HAL_GPIO_WritePin(GPS_EN_GPIO_Port, GPS_EN_Pin, GPIO_PIN_RESET)

#define TEMP_BUFFER_SIZE 1024	
#define RX_BUFFER_MAX_SIZE 2048

/* Private variables ---------------------------------------------------------*/
/* Private user code ---------------------------------------------------------*/
/**
 * 向GPS芯片发送命令语句
 */
void AT6558R_SendCmd(char *cmd)
{
	/**
	 * 计算校验和
	 */
	char fullCmd[128];
	uint16_t checksun = 0;
	size_t len = strlen(cmd);
	for (size_t i = 0; i < len; ++i)
	{
		checksun ^= cmd[i];
	}

	/**
	 * 输出完整的命令字符串
	 */
	sprintf(fullCmd, "$%s*%02X\r\n", cmd, checksun);
	// LOG_DEBUG("%s\r\n", fullCmd);

	/**
	 * 发送命令消息
	 */
	HAL_UART_Transmit(&huart2, (uint8_t *)fullCmd, strlen(fullCmd),
					  HAL_MAX_DELAY);
}

/**
 * @brief GPS进入低功耗模式
 * @param
 * @return
 * @note 芯片有多种工作模式：全工作模式、休眠模式和电池备份模式。
 * 全工作模式：所有电源正常供电，且 ON_OFF 管脚为高电平时，芯片处于全工作模式，进行正常的信号接收和解算。
 * 休眠模式：所有电源正常供电，ON_OFF 管脚拉低，将关闭 DCDC 和内置 LDO，射频电路和基带电路停止工作，进入低功耗休眠状态。当 ON_OFF 管脚拉高后，芯片将自动恢复全工作模式（相当于热启动）
 * 电池备份模式：关闭除 VDD_BK 之外的所有电源，这时只需要极小的电流维持 RTC 时钟和备份 RAM 即可。电源恢复后，导航程序可以从备份 RAM 恢复，以实现快速的热启动
 */
void AT6558R_EnterBatteryBackupMode(void)
{
	/* 拉低GPS-EN引脚，关闭除 VDD_BK 之外的所有电源 */
	GPS_EN_PIN_L;
	Delay_ms(100);

	LOG_DEBUG("GPS enter low power mode!!!");
}

/**
 * @brief GPS退出低功耗模式
 * @param
 * @return
 */
void AT6558R_ExitBatteryBackupMode(void)
{
	/* 使能GPS-EN引脚，打开主电源 */
	GPS_EN_PIN_H;
	Delay_ms(100);

	LOG_DEBUG("GPS wake up!!!");
}

/**
 * 初始化GPS芯片，配置它的参数
 */
void AT6558R_Init(void)
{
	/*引脚、串口已经配置好了*/

	/* 使能GPS-EN引脚，芯片开始工作 */
	GPS_EN_PIN_H;
	Delay_ms(100);

	/**
	 * 配置芯片的参数
	 * 1秒钟更新一次定位信息
	 * 北斗和 GPS 双模
	 */
	AT6558R_SendCmd(GPS_MODE);
	AT6558R_SendCmd(GPS_UPDATE_RATE);
	Delay_ms(100);
}

/**
 * 接受GPS发来的定位数据，拼接成完整数据包
 *  $GNGGA,013050.000,3106.67898,N,12113.52954,E,1,07,3.1,-10.7,M,10.3,M,,*5A
	$GNGLL,3106.67898,N,12113.52954,E,013050.000,A,A*43
	$GNGSA,A,3,10,16,26,194,,,,,,,,,5.2,3.1,4.2,1*0C
	$GNGSA,A,3,13,23,38,,,,,,,,,,5.2,3.1,4.2,4*3F
	$GPGSV,3,1,11,03,20,308,,10,12,183,17,16,27,221,33,25,23,043,,0*61
	$GPGSV,3,2,11,26,59,238,41,28,59,010,,29,31,085,,31,52,320,,0*67
	$GPGSV,3,3,11,32,63,126,44,194,66,109,35,195,08,160,,0*54
	$BDGSV,2,1,06,07,,,37,13,32,220,34,14,15,159,,23,43,269,30,0*42
	$BDGSV,2,2,06,25,63,008,,38,20,197,35,0*78
	核心定位数据RMC 时间,有效,维度,维度方向,经度,经度方向,速度,航向,日期....
	$GNRMC,013050.000,A,3106.67898,N,12113.52954,E,5.19,77.74,160125,,,A,V*31
	$GNVTG,77.74,T,,M,5.19,N,9.61,K,A*13
	$GNZDA,013050.000,16,01,2025,00,00*4C
	$GPTXT,01,01,01,ANTENNA OPEN*25
 */
void AT6558R_ReceiveData(uint8_t *rxBuffer)
{
	uint8_t tempBuffer[TEMP_BUFFER_SIZE];
	uint16_t tempBufferLen;

	uint16_t rxBufferLen = 0;

	/* 接受GPS芯片发来的数据, 接收USART2的信息 */
	memset(rxBuffer, 0, RX_BUFFER_MAX_SIZE);

	// 一直接收数据 => 直到数据完整包含GGA和TXT, 如果接收数据中间出现中断 => 拼接两次接收的数据
	while (1)
	{
		// 判断数据接收完整
		if (strstr((char *)rxBuffer, "GGA") != NULL && strstr((char *)rxBuffer, "TXT") != NULL)
		{
			// 当前一次接收数据完整
			LOG_DEBUG("Receie data completely");
			break;
		}

		/* 接收数据到临时缓冲区 */
		HAL_UARTEx_ReceiveToIdle(&huart2, tempBuffer, TEMP_BUFFER_SIZE - 1, &tempBufferLen, 1000);
		//        AT6558R_ReceiveToIdle(&huart2, gps_buff, TEMP_BUFFER_SIZE, &tempBufferLen, 3000);
		if (tempBufferLen > 0)
		{
			// LOG_DEBUG("Receiving data");
			tempBuffer[tempBufferLen] = '\0';	
			
			if (rxBufferLen + tempBufferLen < RX_BUFFER_MAX_SIZE)
			{
				// 当前接收到数据 => 拼接到大的缓冲区
				memcpy(rxBuffer + rxBufferLen, tempBuffer, tempBufferLen);
				// 记录长度
				rxBufferLen += tempBufferLen;
				/* 在字符串末尾添加 \0 */
				rxBuffer[rxBufferLen] = '\0';
			}
			else
			{
				LOG_DEBUG("Receive data buffer overflow");
				break;					
			}
			
			// 初始化接收缓冲区
			memset(tempBuffer, 0, TEMP_BUFFER_SIZE);
			tempBufferLen = 0;
			
			// Delay_ms(100);
		}
		LOG_DEBUG("rxBufferLen:%d", rxBufferLen);
		LOG_DEBUG("%s", rxBuffer);
	}

	// 打印输出查看gps信息
	// LOG_DEBUG("\n%s", rxBuffer);
}

/**
 * @brief  Receive data in blocking mode until either expected data is received or IDLE event occurs在阻塞模式下接收数据，直到收到预期数据或发生 IDLE 事件
 * @param  USARTx: Pointer to USART peripheral (e.g., USART1, USART2, etc.)
 * @param  pData: Pointer to data buffer (uint8_t or uint16_t)
 * @param  Size: 预期接收的数据元素数量（单位取决于配置）
 * @param  RxLen: 实际接收的数据元素数量（可能 ≤ Size）
 * @param  Timeout: Timeout duration in milliseconds
 * @retval Status: RESET (OK) or SET (Error/Timeout)
 */
// int8_t AT6558R_ReceiveToIdle(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint16_t *RxLen, uint32_t Timeout)
//{
//	 uint32_t tickstart;
//
//	/* Check parameters */
//	if ((huart == NULL) || (pData == NULL) || (Size == 0))
//	{
//		return 1; // Error
//	}
//
//     /* Init tickstart for timeout management */
//     tickstart = HAL_GetTick();
//
//
//	/* Initialize RxLen */
//	*RxLen = 0;
//	uint16_t rxCount = Size;//预期接收的数据元素数量
//	/* Main reception loop */
//	while (rxCount > 0)
//	{
//		/* Check for IDLE event */
//		if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
//		{
//			__HAL_UART_CLEAR_IDLEFLAG(huart);//Clear IDLE flag in ISR
//			/* If data received before IDLE, return */
//			if (*RxLen > 0)
//			{
//				return 0; // Success with IDLE event
//			}
//		}
//
//		/* Check for RXNE (Receive Data Register Not Empty) */
//		if (__HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE))
//		{
//			/* Store data based on format */
//			*pData = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
//			pData++;
//			/* Update counters */
//			*RxLen += 1;
//			rxCount--;
//		}
//
//	      /* Check for the Timeout */
//	      if (Timeout != HAL_MAX_DELAY)
//	      {
//	        if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
//	        {
//	          huart->RxState = HAL_UART_STATE_READY;
//
//	          return HAL_TIMEOUT;
//	        }
//	      }
//	}
//
//     /* Set number of received elements in output parameter : RxLen */
//     *RxLen = Size - rxCount;
//     /* At end of Rx process, restore huart->RxState to Ready */
//     huart->RxState = HAL_UART_STATE_READY;
//	return 0; // Success: received all requested data
// }
